// 函数的类型签名

// 函数声明
function foo(name: string): number {
  return name.length
}

// 函数表达式
const foo2 = function (name: string): number { return name.length }

// 变量函数的声明
const foo3: (name: string) => number = (name) => { return name.length }

// 函数声明类型抽离
type fooFun = (name: string) => number
const foo4: fooFun = function (name: string) { return name.length }

// interface 函数声明 Callable Interface
interface fooFun2 {
  (name: string): number
}

const foo5: fooFun2 = (name: string) => { return name.length }

// void 类型, 返回值为 void 不是 undefinde. 实际值是undefined
const foo6 = () => {}

// 更好的方式， 返回 undefined
const foo7 = (): undefined => { return }

// 可选参数与 rest 参数
function foo8(name: string, age?: number): string {
  return name + age ?? 18
}
foo8('aaa')

// 可选参数默认值
function foo9(name: string, age: number = 18) {
  return name.length + age
}
foo9('bbb')

// rest 参数
function foo10(name: string, ...rest: [string, number]) {
  console.log(name)
  console.log(rest)
}

foo10('ccc', 'sss', 3)

// 我们可以使用 TypeScript 提供的函数重载签名（*Overload Signature*）
function foo11 (foo: number, bar: true) : string
function foo11 (foo: number, bar?: false) : number
function foo11(foo: number, bar?: boolean): string | number {
  if (bar) {
    return String(foo)
  } else {
    return foo * 100
  }
}
// 类型没体现出来这一点，实现关联返回值
// 是按照重载的声明顺序往下查找的。因此在第一个重载声明中，为了与逻辑中保持一致，即在 bar 为 true 时返回 string 类型，这里我们需要将第一个重载声明的 bar 声明为必选的字面量类型。
foo11(100)
foo11(200, true)
foo11(300, false)


// 异步函数、Generator 函数等类型签名
async function asyncFunc(): Promise<void> {}
function * genFun():Iterable<void> {}


// 类与类成员的类型签名
// setting 方法不允许进行返回值类型标注
class Foo {
  prop: string

  constructor(inputProp: string) {
    this.prop = inputProp
  }

  print(addon: string): void {
    console.log(`${this.prop} and ${addon}`)
  }
  get propA(): string {
    return `${this.prop} + A`
  }

  set propA(val: string) {
    this.prop = `${val} + A`
  }
}

// 以上为类声明方式

// 下面为类表达时候方式
const Foo2 = class {
  prop: string
}

// 修饰符

// 索引类型的访问
interface NumberRecord {
  [key: string]: number
}
type propType = NumberRecord[string]

// ReturnType 这个工具类型，只需要知道它会返回一个函数类型中返回值位置的类型：

const func = (input: string) => {
  return input.length > 10;
}

// boolean
type FuncReturnType = ReturnType<typeof func>;